import re
import time

from django.shortcuts import render
from django.db import transaction
from django.db.models import Q

# Create your views here.
from rest_framework import status, exceptions
from rest_framework.response import Response
from rest_framework.views import APIView
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter

from article_app import models
from article_app.filters import ArticleFilter
from article_app.models import Article, Comment, CommentRelation, Message
from article_app.serializers import ArticleSimpleSerializer, ArticleDetailSerializer, CommentSimpleSerializer, \
    CommentDetailSerializer, AdminArticleSimpleSerializer, AdminArticleDetailSerializer, MessageSimpleSerializer
from middlewares.auth import login_and_auth_middleware, CsrfExemptSessionAuthentication, used_time, auth_middleware
from middlewares.auto_speed import speed_limit_middleware, log_middleware
from user_app.models import User
from utils.encode_decode import my_decode
from utils.encode_decode import ShortLink
# 猴子补丁
my_decode = ShortLink().decrypt
from utils.file_helper import upload_image_to_local

from urllib import parse

from utils.pagination import MyPageNumberPagination, MyPageNumberPaginationCursor, MySingalPageNumberPaginationCursor


class ArticleView(APIView):
    """负责获取全部文章上传文章"""

    # #DjangoFilterBackend表示开启筛选，OrderingFilter表示开启排序
    # filter_backends = [DjangoFilterBackend, OrderingFilter]
    filter_backends = [DjangoFilterBackend, OrderingFilter]

    def filter_queryset(self, queryset):
        for backend in list(self.filter_backends):
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset

    filter_class = ArticleFilter
    ordering = ('-is_recommend', '-recommend', '-view_no', '-add_time')

    @log_middleware
    @speed_limit_middleware
    def get(self, request, pk=None):
        """查看所有用户接口"""
        pk = self.decode_id(request.GET.get('pk', None))
        if pk:
            try:
                article = models.Article.objects.filter(pk=pk, is_delete=0, is_check=1, is_public=1).select_related('u_id').first()
                # 查看量+1
                article.view_no += 1
                article.save()
                serializer = ArticleDetailSerializer(article, many=False)
                return Response({"message": "请求成功", "code": 200, "data": {"results": [serializer.data]}})
            except Exception as err:
                return Response({"message": "暂无该文章", "code": 3001, "data": []})
        # 创建分页器
        pagination_class = MyPageNumberPaginationCursor()
        word = request.GET.get('word', None)
        if word:
            articles = models.Article.objects.order_by('-id').filter(is_delete=0, is_public=1, is_check=1).filter(Q(title__icontains=word) | Q(text__icontains=word) | Q(content_text__icontains=word) | Q(tags__icontains=word)).select_related('u_id')
        else:
            articles = models.Article.objects.order_by('-id').filter(is_delete=0, is_public=1, is_check=1).select_related('u_id')
        pager_roles = pagination_class.paginate_queryset(queryset=articles, request=request, view=self)
        bs = ArticleSimpleSerializer(pager_roles, many=True)
        return pagination_class.get_paginated_response(bs.data)

    @log_middleware
    @speed_limit_middleware
    @login_and_auth_middleware
    def post(self, request):
        """上传接口"""
        uid = request.META.get("mini_uid")
        title = parse.unquote(request.data.get("title")).strip(" ")
        mode = parse.unquote(request.data.get("mode", "1"))
        tags = '|'.join(list(set(parse.unquote(request.data.get("tags", "原创")).split('|'))))
        is_public = request.data.get("mode", "0")
        is_public = 1 if (is_public == "1" or is_public == "True" or is_public == "true") else 0
        if len(title) > 100:
            return Response({"message": "标题超出限制长度", "code": status.HTTP_400_BAD_REQUEST})
        text = parse.unquote(request.data.get("text"))
        avatar = parse.unquote(request.data.get("avatar", "/static/image/default.jpg"))
        if not re.match("/static/user_static/.{60,70}", avatar):
            avatar = "/static/image/default.jpg"
        content_text = parse.unquote(request.data.get("text_content"))
        # 对其进行去除标签的处理
        # re.sub('<.*?>([!<]*)>')
        user = User.objects.get(pk=uid)
        article = Article(title=title, text=text, u_id=user, content_text=content_text, head_avatar=avatar, mode=mode, is_public=is_public, tags=tags, add_time=time.time(), change_time=time.time())
        article.save()
        return Response({"message": "上传成功 等待审核结束即可展示", "code": 200})


    @staticmethod
    def decode_id(id_):
        if not id_:
            return None
        id_ = my_decode(id_)
        print(id_)
        return id_ if id_ > 0 else -1


class MyArticleView(APIView):
    """用户操作个人文章"""

    # #DjangoFilterBackend表示开启筛选，OrderingFilter表示开启排序
    # filter_backends = [DjangoFilterBackend, OrderingFilter]
    filter_backends = [DjangoFilterBackend, OrderingFilter]

    def filter_queryset(self, queryset):
        for backend in list(self.filter_backends):
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset

    filter_class = ArticleFilter
    ordering = ('-add_time',)

    @log_middleware
    @speed_limit_middleware
    @login_and_auth_middleware
    def get(self, request):
        """查看所有的文章接口"""
        uid = request.META.get("mini_uid")
        pk = self.decode_id(request.GET.get('pk', None))
        if pk:
            try:
                article = models.Article.objects.filter(pk=pk, is_delete=0, u_id=uid).select_related('u_id').first()
                serializer = ArticleDetailSerializer(article, many=False)
                return Response({"message": "请求成功", "code": 200, "data": {"results": [serializer.data]}})
            except Exception as err:
                return Response({"message": "暂无该文章", "code": 3001, "data": []})
        # 创建分页器
        pagination_class = MySingalPageNumberPaginationCursor()
        articles = models.Article.objects.filter(is_delete=0, u_id=uid).select_related('u_id')
        articles = self.filter_queryset(articles)
        pager_roles = pagination_class.paginate_queryset(queryset=articles, request=request, view=self)
        bs = ArticleSimpleSerializer(pager_roles, many=True)
        return pagination_class.get_paginated_response(bs.data)

    @log_middleware
    @login_and_auth_middleware
    def delete(self, request):
        """删除文章"""
        uid = request.META.get("mini_uid")
        aid = self.decode_id(request.GET.get('aid', None))
        if not models.Article.objects.filter(pk=aid).exists():
            return Response({"message": "暂无该文章", "code": 3001, "data": []})
        obj = models.Article.objects.get(pk=aid)
        obj.is_delete = 1
        obj.save()
        return Response({"message": "删除成功", "code": 200, "data": []})

    @log_middleware
    @speed_limit_middleware
    @login_and_auth_middleware
    def put(self, request):
        """更新文章"""
        uid = request.META.get("mini_uid")
        aid = self.decode_id(request.data.get('aid', ''))
        type_ = request.data.get("type", None)
        print(type_)
        if type_ == '1':
            # 更新私有公开
            if not aid or aid < 0:
                return Response({"message": "更新失败", "code": 3001})
            if Article.objects.get(pk=aid).u_id.id != uid:
                return Response({"message": "更新失败", "code": 3001})
            article = Article.objects.get(pk=aid)
            article.is_public = 0 if article.is_public else 1
            article.save()
            return Response({"message": "更新成功", "code": 200})
        else: 
            text = parse.unquote(request.data.get("text"))
            content_text = parse.unquote(request.data.get("text_content"))
            if (len(text) <= 10 or len(content_text) <= 10):
                return Response({"message": "更新失败 字符太少", "code": 3001})
            title = parse.unquote(request.data.get("title"))
            tags = '|'.join(list(set(parse.unquote(request.data.get("tags", "原创")).split('|'))))
            avatar = parse.unquote(request.data.get("avatar", None))
            if not aid or aid < 0:
                return Response({"message": "更新失败", "code": 3001})
            if Article.objects.get(pk=aid).u_id.id != uid:
                return Response({"message": "更新失败", "code": 3001})
            article = Article.objects.get(pk=aid)
            article.text = text
            article.content_text = content_text
            article.title = title
            if avatar:
                article.head_avatar = avatar
            article.is_check = 0
            article.change_time = time.time()
            article.tags = tags
            article.save()
            return Response({"message": "更新成功 等待审核结束即可展示", "code": 200})


    @staticmethod
    def decode_id(id_):
        if not id_:
            return None
        id_ = my_decode(id_)
        print(id_)
        return id_ if id_ > 0 else -1


class ImageView(APIView):

    authentication_classes = (CsrfExemptSessionAuthentication,)

    def get(self, request):
        """查看所有用户接口"""
        ...
        return Response({"data": []})

    @log_middleware
    @speed_limit_middleware
    @login_and_auth_middleware
    def post(self, request):
        """上传文章图片"""
        image_file = request.FILES.get("upload")
        if not image_file:
            return Response({"message": "上传图片为空", "code": 3001})
        file_name, file_status, info = upload_image_to_local(image_file)
        if not file_status:
            return Response({"message": info, "code": status.HTTP_400_BAD_REQUEST})
        return Response({"message": "图片上传成功", "url": f'/static/user_static/{file_name}', "code": 200})


class AvatarImageView(APIView):

    authentication_classes = (CsrfExemptSessionAuthentication,)

    def get(self, request):
        """查看所有用户接口"""
        ...
        return Response({"data": []})

    @log_middleware
    @speed_limit_middleware
    @login_and_auth_middleware
    def post(self, request):
        """上传文章图片"""
        image_file = request.FILES.get("file")
        if not image_file:
            return Response({"message": "上传图片为空", "code": 201, 'uploaded': False})
        file_name, file_status, info = upload_image_to_local(image_file)
        if not file_status:
            raise exceptions.ValidationError({"message": info, "code": status.HTTP_400_BAD_REQUEST})
        return Response({"message": "封面上传成功", "url": f'/static/user_static/{file_name}'})


class CommentView(APIView):
    """与评论相关的接口"""

    # @used_time
    @log_middleware
    def get(self, request):
        """获取文章的评论"""
        pagination_class = MyPageNumberPaginationCursor()
        aid = self.decode_id(request.GET.get('aid', "1"))
        if not aid: return Response({"message": "success", "code": 200, "data": {}})
        queryset = Comment.objects.order_by('-id').filter(article_id=aid, is_delete=0).select_related('from_uid', 'article_id')
        pagination = pagination_class.paginate_queryset(queryset=queryset, request=request, view=self)
        bs = CommentSimpleSerializer(pagination, many=True)
        return pagination_class.get_paginated_response(bs.data)

    @log_middleware
    @login_and_auth_middleware
    def post(self, request):
        """新增评论"""
        uid = request.META.get("mini_uid")  # 获取uid
        content = request.data.get("content", "")  # 获取评论内容
        if not len(content) or len(content) > 600:
            return Response({"message": "评论失败", "code": 3001})
        article_id = self.decode_id(request.data.get("aid", "1"))  # 获取aid
        if not Article.objects.filter(pk=article_id).exists():
            return Response({"message": "评论失败", "code": 3001})
        reply_id = self.decode_id(request.data.get("cid", None))  # 如果是回复cid
        user = User.objects.get(pk=uid)
        article = Article.objects.get(pk=article_id)
        if not article.is_check:
            # 未经审查 不允许发表评论
            return Response({"message": "评论失败 目前文章处于待审核阶段", "code": 3001})
        if reply_id and reply_id > 0:
            # TODO 都必须成功
            point_1 = transaction.savepoint()
            try:
                new_comment = Comment(content=content, content_text='', article_id=article, from_uid=user, level=2, add_time=time.time())
                new_comment.save()
                parent = Comment.objects.get(pk=reply_id)
                CommentRelation(parent_id=parent, child_id=new_comment).save()
                if user != article.u_id:
                    new_message = Message(from_id=user.id, to_id=article.u_id.id, info=content, need_reply=1, link=article.id, link_com=new_comment.id, message_type="评论回复", add_time=time.time())
                    new_message.save()
                transaction.savepoint_commit(point_1)
            except Exception:
                transaction.savepoint_rollback(point_1)
                return Response({"message": "评论失败", "code": 3001})
        else:
            new_comment = Comment(content=content, content_text='', article_id=article, from_uid=user, add_time=time.time())
            new_comment.save()
            # 这里不是回复
            if user != article.u_id:
                # 通知文章作者有人评论文章
                new_message = Message(from_id=user.id, to_id=article.u_id.id, info=content, need_reply=1, link=article.id, link_com=new_comment.id, message_type="文章留言", add_time=time.time())
                new_message.save()
        # 如果评论人评论的文章是自己的文章，并且不是回复别人的消息， 则加入消息通知

        # 评论+1
        article.comment_no += 1
        article.save()
        # 同时返回最新的这条评论
        queryset = new_comment
        serializer = CommentSimpleSerializer(queryset, many=False)
        return Response({"message": "评论成功", "code": 200, "data": serializer.data})
    
    @log_middleware
    @login_and_auth_middleware
    def delete(self, request):
        """删除评论"""
        ...

    @staticmethod
    def decode_id(id_):
        id_ = my_decode(id_)
        # print('机密', id_)
        return id_ if id_ > 0 else -1

class AgreeArticleView(APIView):
    # @used_time
    @log_middleware
    @login_and_auth_middleware
    def get(self, request):
        """给文章点赞"""
        uid = request.META.get("mini_uid")  # 获取uid
        user = User.objects.get(pk=uid)
        aid = self.decode_id(request.GET.get('aid', "1"))
        if not aid: return Response({"message": "fail", "code": 3001, "data": {}})
        if not models.Article.objects.filter(is_check=1, is_delete=0, pk=aid).exists():
            return Response({"message": "获取失败", "code": 3001})
        one_article = models.Article.objects.get(pk=aid)
        add_ = False
        if models.Agree.objects.filter(from_uid=uid, aim_id=aid).exists():
            agree = models.Agree.objects.filter(from_uid=uid, aim_id=aid, aim_type="article").first()
            agree_status = agree.is_delete ^ 1
            agree.is_delete = agree_status
            if agree_status == 0 or agree_status == "0":
                one_article.agree_no += 1
                add_ = True
            else:
                one_article.agree_no -= 1
                add_ = False
        else:
            agree = models.Agree(from_uid=user, aim_id=aid, aim_type='article')
            one_article.agree_no += 1
            add_ = True
        agree.save()
        one_article.save()
        return Response({"message": "点赞成功" if add_ else "取消成功", "code": 200, "data": []})

    @staticmethod
    def decode_id(id_):
        id_ = my_decode(id_)
        # print('机密', id_)
        return id_ if id_ > 0 else -1


class MessageView(APIView):

    @log_middleware
    @login_and_auth_middleware
    def get(self, request):
        """获取用户消息"""
        uid = request.META.get("mini_uid")  # 获取uid
        queryset = models.Message.objects.filter(to_id=uid, is_check=0)
        pagination_class = MyPageNumberPaginationCursor()
        pagination = pagination_class.paginate_queryset(queryset=queryset, request=request, view=self)
        bs = MessageSimpleSerializer(pagination, many=True)
        return pagination_class.get_paginated_response(bs.data)

    @log_middleware
    @login_and_auth_middleware
    def post(self, request):
        uid = request.META.get("mini_uid")  # 获取uid
        mid = self.decode_id(request.GET.get('mid', "1"))
        user = User.objects.get(pk=uid)
        if models.Message.objects.filter(to_id=uid, pk=mid).exists():
            point_1 = transaction.savepoint()
            try:
                one = models.Message.objects.get(pk=mid)
                one.is_check = 1
                one.save()
                comment = request.data.get('comment', 'xxx')
                # 回复内容
                new_message = Message(from_id=uid, to_id=one.from_id, info=comment, need_reply=1, link=one.link, link_com=one.link_com, message_type="消息回复")
                new_message.save()
                if Article.objects.filter(pk=one.link).exists():
                    article = Article.objects.get(pk=one.link)
                    new_comment = Comment(article_id=article, from_uid=user, content=comment, add_time=time.time(), level=2)
                    new_comment.save()
                    old_comment = Comment.objects.get(pk=one.link_com)
                    new_comment_relation = CommentRelation(parent_id=old_comment, child_id=new_comment)
                    new_comment_relation.save()
                    transaction.savepoint_commit(point_1)
                return Response({"message": "success", "code": 200, "data": []})
            except Exception as e:
                print(str(e))
                transaction.savepoint_rollback(point_1)
                return Response({"message": "fail", "code": 30001, "data": []})
        else:
            return Response({"message": "fail", "code": 30001, "data": []})

    @log_middleware
    @login_and_auth_middleware
    def put(self, request):
        uid = request.META.get("mini_uid")  # 获取uid
        mid = self.decode_id(request.GET.get('mid', "1"))
        if models.Message.objects.filter(to_id=uid, pk=mid).exists():
            one = models.Message.objects.get(pk=mid)
            one.is_check = 1
            one.save()
            return Response({"message": "success", "code": 200, "data": []})
        else:
            return Response({"message": "fail", "code": 30001, "data": []})

    @staticmethod
    def decode_id(id_):
        id_ = my_decode(id_)
        # print('机密', id_)
        return id_ if id_ > 0 else -1


# 为超级用户管理员配置视图
class SuperAdminView(APIView):
    """
    为管理员提供审查用户文章内容的接口
    """

    @log_middleware
    @login_and_auth_middleware
    @auth_middleware(10)
    def get(self, request):
        uid = request.META.get("mini_uid")  # 获取uid
        queryset = models.Article.objects.filter(is_check=0, is_delete=0).all()
        pagination_class = MyPageNumberPaginationCursor()
        pagination = pagination_class.paginate_queryset(queryset=queryset, request=request, view=self)
        bs = AdminArticleSimpleSerializer(pagination, many=True)
        return pagination_class.get_paginated_response(bs.data)
        # return Response({"message": "获取成功", "code": 200, "data": []})
    
    @log_middleware
    @login_and_auth_middleware
    @auth_middleware(10)
    def post(self, request):
        aid = self.decode_id(request.GET.get('aid', "1"))
        print(aid, 'aid>>>')
        if not models.Article.objects.filter(is_delete=0, pk=aid).exists():
            return Response({"message": "获取失败", "code": 3001})
        else:
            articles = models.Article.objects.get(pk=aid)
            serializer = AdminArticleDetailSerializer(articles)
            return Response({"data": serializer.data})
    
    @log_middleware
    @login_and_auth_middleware
    @auth_middleware(10)
    def put(self, request):
        uid = request.META.get("mini_uid")  # 获取uid
        aid = self.decode_id(request.GET.get('aid', "1"))
        if not models.Article.objects.filter(is_check=0, is_delete=0, pk=aid).exists():
            return Response({"message": "修改失败", "code": 3001})
        else:
            point_1 = transaction.savepoint()
            try:
                is_valid = request.GET.get('is_valid', None)
                word = request.GET.get('word', '')
                articles = models.Article.objects.get(pk=aid)
                articles.is_check = 1 if is_valid == "true" else -1
                articles.word = word
                articles.save()
                new_message = Message(from_id=0, to_id=articles.u_id.id, need_reply=0, info='文章已通过' if is_valid == 'true' else word, link=0, link_com=0, add_time=time.time())
                new_message.save()
                transaction.savepoint_commit(point_1)
                return Response({"message": "修改成功", "code": 200})
            except Exception:
                transaction.savepoint_rollback(point_1)
                return Response({"message": "修改失败", "code": 3001})

    
    @staticmethod
    def decode_id(id_):
        id_ = my_decode(id_)
        return id_ if id_ > 0 else -1
